package com.creditease.tmsp.common.web;

import java.beans.PropertyEditorSupport;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;

import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.creditease.tmsp.common.beanvalidator.BeanValidators;
import com.creditease.tmsp.common.persistence.IdGenerator;
import com.creditease.tmsp.common.service.MyBatisBaseService;
import com.creditease.tmsp.common.utils.DateUtils;
import com.creditease.tmsp.modules.sys.entity.SysUser;
import com.creditease.tmsp.modules.sys.security.SystemAuthorizingRealm.Principal;
import com.creditease.tmsp.modules.sys.service.UserService;
import com.github.miemiedev.mybatis.paginator.domain.Order;
import com.github.miemiedev.mybatis.paginator.domain.PageBounds;

/**
 * 控制器支持类
 * @author 
 * @version 
 */
public abstract class BaseController {

	/**
	 * 日志对象
	 */
	protected Logger logger = LoggerFactory.getLogger(getClass());
	
	/**
	 * 验证Bean实例对象
	 */
	@Autowired
	protected Validator validator;

	@Autowired
	protected UserService userService;
	/**
	 * 服务端参数有效性验证
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功：返回true；严重失败：将错误信息添加到 message 中
	 */
	protected boolean beanValidator(Model model, Object object, Class<?>... groups) {
		try{
			BeanValidators.validateWithException(validator, object, groups);
		}catch(ConstraintViolationException ex){
			List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			addMessage(model, list.toArray(new String[]{}));
			return false;
		}
		return true;
	}
	
	/**
	 * 服务端参数有效性验证
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功：返回true；严重失败：将错误信息添加到 flash message 中
	 */
	protected boolean beanValidator(RedirectAttributes redirectAttributes, Object object, Class<?>... groups) {
		try{
			BeanValidators.validateWithException(validator, object, groups);
		}catch(ConstraintViolationException ex){
			List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			addMessage(redirectAttributes, list.toArray(new String[]{}));
			return false;
		}
		return true;
	}
	
	/**
	 * 添加Model消息
	 * @param messages 消息
	 */
	protected void addMessage(Model model, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages){
			sb.append(message).append(messages.length>1?"<br/>":"");
		}
		model.addAttribute("message", sb.toString());
	}
	
	/**
	 * 添加Flash消息
     * @param messages 消息
	 */
	protected void addMessage(RedirectAttributes redirectAttributes, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages){
			sb.append(message).append(messages.length>1?"<br/>":"");
		}
		redirectAttributes.addFlashAttribute("message", sb.toString());
	}
	
	/**
	 * 初始化数据绑定
	 * 1. 将所有传递进来的String进行HTML编码，防止XSS攻击
	 * 2. 将字段中Date类型转换为String类型
	 */
	@InitBinder
	protected void initBinder(WebDataBinder binder) {
		// String类型转换，将所有传递进来的String进行HTML编码，防止XSS攻击
		binder.registerCustomEditor(String.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				setValue(text == null ? null : StringEscapeUtils.escapeHtml4(text.trim()));
			}
			@Override
			public String getAsText() {
				Object value = getValue();
				return value != null ? value.toString() : "";
			}
		});
		// Date 类型转换
		binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				setValue(DateUtils.parseDate(text));
			}
		});
	}
	
	/**
	 * @Description:Mybatis分页需要的参数
	 * @author：
	 * @param request
	 * @return
	 */
	protected PageBounds requestPageBounds(HttpServletRequest request) {
		
		int pageSize = 10;
		int pageNo = 1;
		String sortString = request.getParameter("sortString");
		String size = request.getParameter("pageSize");
		if(StringUtils.isNumeric(size)){
			pageSize = Integer.parseInt(size);
		}
		String no = request.getParameter("pageNo");
		if(StringUtils.isNumeric(no)){
			pageNo =  Integer.parseInt(no);
		}	
        
        request.setAttribute("pageNo", pageNo);
        request.setAttribute("pageSize", pageSize);
		return new PageBounds(pageNo, pageSize , Order.formString(sortString));
		
	}
	
	/**
	 * @Description:设置MyBatis搜索参数,自动将bean转换成map
	 * @author：
	 * @param obj
	 * @return
	 */
	protected  Map<String,Object> convertBeanToMap(Object obj) {
		  Map<String,Object> reMap = new HashMap<String,Object>();
		  if (obj == null){
			  return null;  
		  } 		      
		  Field[] fields = obj.getClass().getDeclaredFields();
		  try {
		      for(int i=0;i<fields.length;i++){
				    try {
					     Field f = obj.getClass().getDeclaredField(fields[i].getName());
					     f.setAccessible(true);
					     Object o = f.get(obj);
					     if(o!=null){
					    	 reMap.put(fields[i].getName(), o);
					     }					     
				    } catch (Exception e) {
				         e.printStackTrace();
				    }
		     }
		  } catch (SecurityException e) {
		       e.printStackTrace();
		  } 
		  return reMap;
    }
	
	/**
	 * @Description:保存修改通用方法,如果id存在则update,否则设置id和其他基础属性并执行save
	 * @author：
	 * @param service
	 * @param obj
	 * @throws Exception
	 */
	protected void saveOrUpdate(MyBatisBaseService service,Object obj) throws Exception {
		
		 Field id = obj.getClass().getDeclaredField("id");
		 id.setAccessible(true);
		 String idValue = id.get(obj).toString();

    	 if(StringUtils.isNotBlank(idValue)){
    		service.update(obj);
    	 }else{
    		//设置id
    		id.set(obj, IdGenerator.getId());
    		//如果存在createTime和delFlag属性分别为他们设置默认值
			Field[] fields = obj.getClass().getDeclaredFields();
			for(int i=0;i<fields.length;i++){			    	
			    Field f = obj.getClass().getDeclaredField(fields[i].getName());
			    f.setAccessible(true);
			    if(fields[i].getName().equals("createTime")){
			        f.set(obj, new Date());
			    }
				if(fields[i].getName().equals("delFlag")){
					f.set(obj, "0");
				}
			} 
			//保存实体
			service.save(obj);
	     }
    }

	protected Principal getPrincipal() {
		Principal principal = (Principal) SecurityUtils.getSubject().getPrincipal();
		return principal;
	}
	protected SysUser getCrrentUser(){
		
		Principal principal = getPrincipal();
		SysUser user = userService.getByLoginName(principal.getLoginName());
		return user;
	}
}
